package com.yupi.springbootinit.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.exception.BusinessException;
import com.yupi.springbootinit.mapper.*;
import com.yupi.springbootinit.model.dto.production.printingrecord.CompleteCleaningRequest;
import com.yupi.springbootinit.model.dto.production.printingrecord.StartCleaningRequest;
import com.yupi.springbootinit.model.entity.*;
import com.yupi.springbootinit.model.vo.production.CleaningRecordVO;
import com.yupi.springbootinit.service.ProductionCleaningService;
import com.yupi.springbootinit.service.workflow.WorkflowTaskCreationService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Date;

/**
 * 生产清机服务实现
 */
@Slf4j
@Service
public class ProductionCleaningServiceImpl implements ProductionCleaningService {

    // ==================== 常量定义 ====================
    private static final String STATUS_IN_PROGRESS = "IN_PROGRESS";
    private static final String STATUS_DONE = "DONE";
    private static final String EXEC_CLEANING = "PREP_CLEANING";
    private static final String EVT_START = "START";
    private static final String EVT_COMPLETE = "COMPLETE";

    // ==================== 依赖注入 ====================
    @Resource
    private WorkflowTaskMapper workflowTaskMapper;
    @Resource
    private ProcessBatchMapper processBatchMapper;
    @Resource
    private ProductionOperationRecordMapper productionOperationRecordMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private WorkflowTaskCreationService taskCreationService;

    // ==================== 接口实现 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean startPowderCleaning(StartCleaningRequest request, Long loginUserId, String loginUserName) {
        if (request == null || request.getTaskId() == null) {
            log.warn("烘粉清机开始参数不合法: request={}", request);
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不合法");
        }
        if (StringUtils.isBlank(request.getOperatorName())) {
            log.warn("烘粉清机开始参数不合法: operatorName is blank");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "操作员姓名不能为空");
        }

        Long taskId = request.getTaskId();
        WorkflowTask task = workflowTaskMapper.selectById(taskId);
        if (task == null || task.getIsDelete() == 1) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "任务不存在");
        }

        // 检查任务状态
        String taskStatus = task.getTaskStatus();
        if (!"PENDING".equals(taskStatus) && !STATUS_IN_PROGRESS.equals(taskStatus)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR,
                    "任务状态不正确，当前状态：" + taskStatus);
        }

        Long batchId = extractBatchIdFromTask(task);
        ProcessBatch batch = batchId != null ? processBatchMapper.selectById(batchId) : null;
        OperatorInfo operator = getOperatorInfo(
                request.getOperatorId(),
                request.getOperatorName(),
                request.getOperatorAccount()
        );

        LocalDateTime now = LocalDateTime.now();
        ProductionOperationRecord startRecord = new ProductionOperationRecord();
        startRecord.setTaskId(taskId);
        startRecord.setBatchId(batchId);
        startRecord.setStepId(null);
        startRecord.setOperationSeq(null);
        startRecord.setExecType(EXEC_CLEANING);
        startRecord.setEventType(EVT_START);
        startRecord.setEventTime(toDate(now));
        startRecord.setOperatorId(operator.getOperatorId());
        startRecord.setOperatorName(operator.getOperatorName());
        startRecord.setOperatorCode(operator.getOperatorAccount());
        startRecord.setCreatedBy(loginUserId);
        startRecord.setCreatedByName(loginUserName);
        startRecord.setRemark(buildCleaningRemark(batch, request.getRemark()));

        int rows = productionOperationRecordMapper.insert(startRecord);
        if (rows > 0) {
            // 更新任务状态为IN_PROGRESS
            UpdateWrapper<WorkflowTask> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", taskId)
                    .set("taskStatus", STATUS_IN_PROGRESS)
                    .set("updateTime", now);
            workflowTaskMapper.update(null, updateWrapper);

            log.info("烘粉清机已开始: taskId={}, batchId={}, operator={}({}), recordedBy={}",
                    taskId, batchId, operator.getOperatorName(),
                    operator.getOperatorAccount(), loginUserName);
        }
        return rows > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean completePowderCleaning(CompleteCleaningRequest request, Long loginUserId, String loginUserName) {
        if (request == null || request.getTaskId() == null) {
            log.warn("烘粉清机完成参数不合法: request={}", request);
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不合法");
        }
        if (request.getIsNormal() == null) {
            log.warn("烘粉清机完成参数不合法: isNormal is null");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请选择是否正常完成");
        }
        if (Boolean.FALSE.equals(request.getIsNormal()) && StringUtils.isBlank(request.getRemark())) {
            log.warn("烘粉清机完成参数不合法: isNormal=false but remark is blank");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "异常完成必须填写备注");
        }

        Long taskId = request.getTaskId();
        WorkflowTask task = workflowTaskMapper.selectById(taskId);
        if (task == null || task.getIsDelete() == 1) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "任务不存在");
        }

        // 查询开始记录
        LambdaQueryWrapper<ProductionOperationRecord> qw = new LambdaQueryWrapper<>();
        qw.eq(ProductionOperationRecord::getTaskId, taskId)
                .eq(ProductionOperationRecord::getExecType, EXEC_CLEANING)
                .eq(ProductionOperationRecord::getEventType, EVT_START)
                .eq(ProductionOperationRecord::getIsDelete, 0)
                .orderByDesc(ProductionOperationRecord::getEventTime)
                .last("LIMIT 1");
        ProductionOperationRecord startRecord = productionOperationRecordMapper.selectOne(qw);
        if (startRecord == null) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "未找到烘粉清机开始记录");
        }

        // 检查是否已完成
        LambdaQueryWrapper<ProductionOperationRecord> completeQw = new LambdaQueryWrapper<>();
        completeQw.eq(ProductionOperationRecord::getTaskId, taskId)
                .eq(ProductionOperationRecord::getExecType, EXEC_CLEANING)
                .eq(ProductionOperationRecord::getEventType, EVT_COMPLETE)
                .eq(ProductionOperationRecord::getIsDelete, 0);
        Long completeCount = productionOperationRecordMapper.selectCount(completeQw);
        if (completeCount != null && completeCount > 0) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "烘粉清机已完成，不可重复操作");
        }

        LocalDateTime now = LocalDateTime.now();
        ProductionOperationRecord completeRecord = new ProductionOperationRecord();
        completeRecord.setTaskId(taskId);
        completeRecord.setBatchId(startRecord.getBatchId());
        completeRecord.setStepId(null);
        completeRecord.setOperationSeq(null);
        completeRecord.setExecType(EXEC_CLEANING);
        completeRecord.setEventType(EVT_COMPLETE);
        completeRecord.setEventTime(toDate(now));
        completeRecord.setOperatorId(startRecord.getOperatorId());
        completeRecord.setOperatorName(startRecord.getOperatorName());
        completeRecord.setOperatorCode(startRecord.getOperatorCode());
        completeRecord.setCreatedBy(loginUserId);
        completeRecord.setCreatedByName(loginUserName);

        String remarkText = request.getIsNormal() ? "正常完成" : "异常完成";
        if (StringUtils.isNotBlank(request.getRemark())) {
            remarkText += ": " + request.getRemark();
        }
        completeRecord.setRemark(remarkText);

        int rows = productionOperationRecordMapper.insert(completeRecord);
        if (rows > 0) {
            // 更新任务状态为DONE
            UpdateWrapper<WorkflowTask> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", taskId)
                    .set("taskStatus", STATUS_DONE)
                    .set("completedTime", now)
                    .set("completionRemark", remarkText)
                    .set("updateTime", now);
            int updateRows = workflowTaskMapper.update(null, updateWrapper);

            log.info("烘粉清机任务状态更新: taskId={}, batchId={}, updateRows={}, status=DONE",
                    taskId, task.getBizId(), updateRows);

            // 清机完成后，创建生产工单任务
            if ("PRODUCTION_PREP_CLEANING".equals(task.getTaskType())
                    && "PROCESS_BATCH".equals(task.getBizType())) {
                try {
                    ProcessBatch batch = processBatchMapper.selectById(task.getBizId());
                    String productName = batch != null ? batch.getProductName() : task.getProductName();

                    taskCreationService.createProductionWorkorderTaskForBatch(
                            task.getBizId(),
                            task.getBizNumber(),
                            productName,
                            startRecord.getOperatorId(),
                            startRecord.getOperatorName()
                    );

                    log.info("清机完成后成功创建生产工单任务: taskId={}, batchId={}, productName={}",
                            taskId, task.getBizId(), productName);
                } catch (Exception e) {
                    log.error("清机完成后创建生产工单任务失败，batchId={}", task.getBizId(), e);
                    throw new BusinessException(ErrorCode.OPERATION_ERROR,
                            "创建生产工单任务失败: " + e.getMessage());
                }
            }

            log.info("烘粉清机已完成: taskId={}, isNormal={}, recordedBy={}",
                    taskId, request.getIsNormal(), loginUserName);
        } else {
            log.warn("烘粉清机完成记录插入失败: taskId={}", taskId);
        }
        return rows > 0;
    }

    @Override
    public CleaningRecordVO getCleaningRecord(Long taskId) {
        if (taskId == null) return null;

        Long batchId = extractBatchIdFromTask(taskId);
        if (batchId == null) {
            log.warn("无法提取 batchId: taskId={}", taskId);
            return null;
        }

        // 根据 batchId 查询清机开始记录
        LambdaQueryWrapper<ProductionOperationRecord> startQw = new LambdaQueryWrapper<>();
        startQw.eq(ProductionOperationRecord::getBatchId, batchId)
                .eq(ProductionOperationRecord::getExecType, EXEC_CLEANING)
                .eq(ProductionOperationRecord::getEventType, EVT_START)
                .eq(ProductionOperationRecord::getIsDelete, 0)
                .orderByDesc(ProductionOperationRecord::getEventTime)
                .last("LIMIT 1");
        ProductionOperationRecord startRecord = productionOperationRecordMapper.selectOne(startQw);
        if (startRecord == null) {
            log.debug("未找到清机开始记录: taskId={}, batchId={}", taskId, batchId);
            return null;
        }

        // 根据 batchId 查询清机完成记录
        LambdaQueryWrapper<ProductionOperationRecord> completeQw = new LambdaQueryWrapper<>();
        completeQw.eq(ProductionOperationRecord::getBatchId, batchId)
                .eq(ProductionOperationRecord::getExecType, EXEC_CLEANING)
                .eq(ProductionOperationRecord::getEventType, EVT_COMPLETE)
                .eq(ProductionOperationRecord::getIsDelete, 0)
                .orderByDesc(ProductionOperationRecord::getEventTime)
                .last("LIMIT 1");
        ProductionOperationRecord completeRecord = productionOperationRecordMapper.selectOne(completeQw);

        CleaningRecordVO vo = new CleaningRecordVO();
        vo.setTaskId(taskId);
        vo.setBatchId(batchId);
        vo.setOperatorName(startRecord.getOperatorName());
        vo.setStartTime(toLocalDateTime(startRecord.getEventTime()));

        if (completeRecord != null) {
            vo.setEndTime(toLocalDateTime(completeRecord.getEventTime()));
            vo.setStatus("COMPLETED");
            vo.setIsNormal(completeRecord.getRemark() != null
                    && completeRecord.getRemark().contains("正常完成"));
            vo.setRemark(completeRecord.getRemark());

            LocalDateTime st = toLocalDateTime(startRecord.getEventTime());
            LocalDateTime et = toLocalDateTime(completeRecord.getEventTime());
            if (st != null && et != null) {
                long minutes = java.time.Duration.between(st, et).toMinutes();
                vo.setDurationMinutes(minutes);
            }
        } else {
            vo.setStatus("IN_PROGRESS");
            LocalDateTime st = toLocalDateTime(startRecord.getEventTime());
            if (st != null) {
                long minutes = java.time.Duration.between(st, LocalDateTime.now()).toMinutes();
                vo.setDurationMinutes(minutes);
            }
        }

        log.debug("获取清机记录成功: taskId={}, batchId={}, status={}",
                taskId, batchId, vo.getStatus());
        return vo;
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 从任务中提取批次ID
     */
    private Long extractBatchIdFromTask(Long taskId) {
        if (taskId == null) return null;
        WorkflowTask task = workflowTaskMapper.selectById(taskId);
        return extractBatchIdFromTask(task);
    }

    private Long extractBatchIdFromTask(WorkflowTask task) {
        if (task != null && "PROCESS_BATCH".equals(task.getBizType())) {
            return task.getBizId();
        }
        return task != null ? task.getBizId() : null;
    }

    /**
     * 构建清机备注
     */
    private String buildCleaningRemark(ProcessBatch batch, String userRemark) {
        if (batch == null) return userRemark;

        StringBuilder sb = new StringBuilder();
        if (batch.getPowderModel() != null) {
            sb.append("粉末型号:").append(batch.getPowderModel());
        }
        if (batch.getPowderWeight() != null) {
            if (sb.length() > 0) sb.append("; ");
            sb.append("烘粉重量:").append(batch.getPowderWeight()).append("kg");
        }
        if (batch.getCleaningDeviceName() != null) {
            if (sb.length() > 0) sb.append("; ");
            sb.append("清机设备:").append(batch.getCleaningDeviceName());
        }
        if (StringUtils.isNotBlank(userRemark)) {
            if (sb.length() > 0) sb.append("; ");
            sb.append(userRemark);
        }
        return sb.toString();
    }

    /**
     * 获取操作员信息
     */
    private OperatorInfo getOperatorInfo(Long operatorId, String operatorName, String operatorAccount) {
        OperatorInfo info = new OperatorInfo();
        if (operatorId != null) {
            try {
                User user = userMapper.selectById(operatorId);
                if (user != null) {
                    info.setOperatorId(user.getId());
                    info.setOperatorName(user.getUserName());
                    info.setOperatorAccount(user.getUserAccount());
                    return info;
                }
            } catch (Exception e) {
                log.warn("查询操作员信息失败: operatorId={}", operatorId, e);
            }
        }
        info.setOperatorId(operatorId);
        info.setOperatorName(operatorName);
        info.setOperatorAccount(operatorAccount);
        return info;
    }

    /**
     * LocalDateTime 转 Date
     */
    private Date toDate(LocalDateTime localDateTime) {
        if (localDateTime == null) return null;
        return Date.from(localDateTime.atZone(java.time.ZoneId.systemDefault()).toInstant());
    }

    /**
     * Date 转 LocalDateTime
     */
    private LocalDateTime toLocalDateTime(Date date) {
        if (date == null) return null;
        return date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime();
    }

    // ==================== 内部类 ====================

    /**
     * 操作员信息
     */
    @lombok.Data
    private static class OperatorInfo {
        private Long operatorId;
        private String operatorName;
        private String operatorAccount;
    }
}